package tt.dz.biz.service.account;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Resource;
import org.springframework.util.CollectionUtils;
import tt.dz.biz.dao.account.AccountingDAO;
import tt.dz.biz.service.user.OfflineAccountService;
import tt.dz.common.BigDecimalUtil;
import tt.dz.common.BusinessException;
import tt.dz.common.DzConstants;
import tt.dz.common.DzConstants.balType;
import tt.dz.common.DzConstants.balanceFlag;
import tt.dz.common.DzConstants.borrowOrLoanFlag;
import tt.dz.common.DzConstants.isCostService;
import tt.dz.common.DzConstants.isSelfMerchant;
import tt.dz.common.DzConstants.realTime;
import tt.dz.common.DzConstants.receiveOrPay;
import tt.dz.common.DzConstants.subjectType;
import tt.dz.common.LogUtil;
import tt.dz.vo.AccountDetailVO;
import tt.dz.vo.AccountingRuleVO;
import tt.dz.vo.MerchAccountDividendVO;
import tt.dz.vo.MerchantSubjectAccVO;
import tt.dz.vo.MerchantVO;
import tt.dz.vo.SubjectVO;
import tt.dz.vo.TranInfoVO;
import tt.dz.vo.TranSubVO;

public class OnlineCardToMerchantPOJO
  extends AccountDividendPOJO
{
  @Resource(name="offlineAccountService")
  private OfflineAccountService offlineAccountService;
  private AccountDetailVO accountDetailVO;
  
  public OnlineCardToMerchantPOJO() {}
  
  public OnlineCardToMerchantPOJO(TranInfoVO tranInfoVO)
    throws Exception
  {
    super(tranInfoVO);
    init();
  }
  
  private boolean isSaveMoney = false;
  
  public OnlineCardToMerchantPOJO init()
    throws Exception
  {
    try
    {
      if (null != this.tranInfoVO.getReceiver())
      {
        this.platMerchantCode = this.tranInfoVO.getReceiver();
      }
      else
      {
        if (CollectionUtils.isEmpty(this.tranSubVOList)) {
          throw new BusinessException("未找到自营运营商参与交易，交易数据异常。");
        }
        for (TranSubVO tranSubVO : this.tranSubVOList) {
          if (DzConstants.isSelfMerchant.SELF.value().equals(tranSubVO.getReceiverIsSelf()))
          {
            this.platMerchantCode = tranSubVO.getReceiver();
            break;
          }
        }
      }
      if (null == this.tranInfoVO.getPayer()) {
        throw new BusinessException("交易数据异常，实际支付方为空。");
      }
      if (CollectionUtils.isEmpty(this.tranSubVOList)) {
        this.isSaveMoney = true;
      } else {
        this.isSaveMoney = false;
      }
    }
    catch (Exception e)
    {
      LogUtil.error("初始化交易记录失败", e);
      throw e;
    }
    return this;
  }
  
  private OnlineCardToMerchantPOJO assemblePayerAccountDetail()
    throws Exception
  {
    try
    {
      this.accountDetailVO = new AccountDetailVO();
      this.accountDetailVO.setUserId(this.tranInfoVO.getPayer());
      this.accountDetailVO.setAccountingDate(this.accountingDate);
      this.accountDetailVO.setTradeNo(this.tranInfoVO.getTradeNo());
      this.accountDetailVO.setMerchantCode(this.platMerchantCode);
      this.accountDetailVO.setServiceNo(this.tranInfoVO.getServiceNo());
      this.accountDetailVO.setPlatTime(this.platTime);
      this.accountDetailVO.setPaymentAmount(this.tranInfoVO.getPaymentAmount());
      this.accountDetailVO.setPayTypeCode(this.tranInfoVO.getPayTypeCode());
      if (this.isSaveMoney) {
        this.accountDetailVO.setPayFlag(DzConstants.receiveOrPay.RECEIVE.value());
      } else {
        this.accountDetailVO.setPayFlag(DzConstants.receiveOrPay.PAY.value());
      }
    }
    catch (Exception e)
    {
      LogUtil.error("初始化个人账户明细失败", e);
      throw e;
    }
    return this;
  }
  
  private OnlineCardToMerchantPOJO assembleReceiveAccountDetail()
    throws Exception
  {
    try
    {
      if (this.isSaveMoney) {
        return this;
      }
      TranInfoVO tmp = null;
      TranSubVO tranSubVO = null;
      MerchantVO merchantVO = null;
      TranSubVO costTranSubVO = null;
      for (int i = 0; i < this.tranSubVOList.size(); i++)
      {
        tranSubVO = (TranSubVO)this.tranSubVOList.get(i);
        if ((DzConstants.isCostService.IS_COST_SERVICE.value().equals(tranSubVO.getIsCost())) && 
          (DzConstants.isSelfMerchant.SELF.value().equals(tranSubVO.getReceiverIsSelf())))
        {
          costTranSubVO = new TranSubVO();
          merchantVO = this.accountingDAO.queryCostServiceMerchant(tranSubVO.getServiceNo());
          costTranSubVO.setPaymentAmount(tranSubVO.getPaymentAmount());
          costTranSubVO.setReceiver(merchantVO.getMerchantCode());
          costTranSubVO.setReceiverBalType(merchantVO.getBalType());
          costTranSubVO.setServiceNo(tranSubVO.getServiceNo());
          costTranSubVO.setReceiverIsSelf(DzConstants.isSelfMerchant.COPERATION.value());
          costTranSubVO.setPayer(tranSubVO.getReceiver());
          tranSubVO = costTranSubVO;
        }
        this.merchantTranSubList.add(tranSubVO);
        if (DzConstants.isSelfMerchant.COPERATION.value().equals(tranSubVO.getReceiverIsSelf()))
        {
          if (this.totalAmount.containsKey(tranSubVO.getReceiver()))
          {
            tmp = (TranInfoVO)this.totalAmount.get(tranSubVO.getReceiver());
            tmp.setPaymentAmount(
              BigDecimalUtil.add(tmp.getPaymentAmount(), tranSubVO.getPaymentAmount()));
          }
          else
          {
            tmp = new TranInfoVO();
            tmp.setServiceNo(this.tranInfoVO.getServiceNo());
            tmp.setChannelCode(this.tranInfoVO.getChannelCode());
            tmp.setPaymentAmount(tranSubVO.getPaymentAmount());
            tmp.setReceiver(tranSubVO.getReceiver());
            tmp.setReceiverType(tranSubVO.getReceiverType());
            tmp.setPayStateCode(this.tranInfoVO.getPayStateCode());
            this.totalAmount.put(tmp.getReceiver(), tmp);
          }
          if (DzConstants.realTime.YES.value().equals(tranSubVO.getReceiverBalType())) {
            if (this.needRealTimeTotalAmount.containsKey(tranSubVO.getReceiver()))
            {
              tmp = (TranInfoVO)this.needRealTimeTotalAmount.get(tranSubVO.getReceiver());
              tmp.setPaymentAmount(tmp.getPaymentAmount().add(tranSubVO.getPaymentAmount()));
            }
            else
            {
              tmp = new TranInfoVO();
              tmp.setServiceNo(this.tranInfoVO.getServiceNo());
              tmp.setChannelCode(this.tranInfoVO.getChannelCode());
              tmp.setPaymentAmount(tranSubVO.getPaymentAmount());
              tmp.setReceiver(tranSubVO.getReceiver());
              tmp.setReceiverType(tranSubVO.getReceiverType());
              tmp.setPayStateCode(this.tranInfoVO.getPayStateCode());
              this.needRealTimeTotalAmount.put(tmp.getReceiver(), tmp);
            }
          }
        }
      }
    }
    catch (Exception e)
    {
      LogUtil.error("组装收款人的账户分录信息异常", e);
      throw e;
    }
    return this;
  }
  
  private OnlineCardToMerchantPOJO addTotalaccount()
    throws Exception
  {
    try
    {
      if (!this.isSaveMoney)
      {
        TranInfoVO tmp = null;
        MerchAccountDividendVO detail = null;
        MerchantSubjectAccVO mertchSubject = null;
        AccountingRuleVO rule;
        AccountingRuleVO relateRule;
        if (!CollectionUtils.isEmpty(this.totalAmount))
        {
          Set<Map.Entry<String, TranInfoVO>> tranInfoSet = this.totalAmount.entrySet();
          
          rule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.ASSETS
            .value(), DzConstants.balType.PERIODIC_CLEARING.value());
          
          relateRule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO
            .getServiceNo(), DzConstants.subjectType.LIABILITIES.value(), DzConstants.balType.PERIODIC_CLEARING
            .value());
          for (Map.Entry<String, TranInfoVO> entry : tranInfoSet)
          {
            tmp = (TranInfoVO)entry.getValue();
            detail = new MerchAccountDividendVO();
            detail.setTradeNo(this.tranInfoVO.getTradeNo());
            detail.setMerchantCode(tmp.getReceiver());
            detail.setSubjectCode(rule.getSubjectCode());
            detail.setSubSubjectCode(rule.getSubSubjectCode());
            detail.setLoanFlag(rule.getLoanFlag());
            detail.setAmount(tmp.getPaymentAmount());
            
            detail.setMerchantCode1(this.platMerchantCode);
            detail.setAccountingDate(this.accountingDate);
            
            mertchSubject = new MerchantSubjectAccVO();
            mertchSubject.setMerchantCode(detail.getMerchantCode());
            mertchSubject.setSubSubjectCode(detail.getSubSubjectCode());
            if (DzConstants.balanceFlag.REDUCTION.value().equals(rule.getBalanceFlag())) {
              mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), detail.getAmount()));
            } else {
              mertchSubject.setAcctBal(detail.getAmount());
            }
            this.merchAccountDividendList.add(detail);
            this.merchantSubjectList.add(mertchSubject);
            
            detail = new MerchAccountDividendVO();
            mertchSubject = new MerchantSubjectAccVO();
            detail.setTradeNo(this.tranInfoVO.getTradeNo());
            detail.setMerchantCode(this.platMerchantCode);
            detail.setSubjectCode(relateRule.getSubjectCode());
            detail.setSubSubjectCode(relateRule.getSubSubjectCode());
            detail.setLoanFlag(relateRule.getLoanFlag());
            detail.setAmount(tmp.getPaymentAmount());
            
            detail.setMerchantCode1(tmp.getReceiver());
            detail.setAccountingDate(this.accountingDate);
            mertchSubject = new MerchantSubjectAccVO();
            mertchSubject.setMerchantCode(detail.getMerchantCode());
            mertchSubject.setSubSubjectCode(detail.getSubSubjectCode());
            if (DzConstants.balanceFlag.REDUCTION.value().equals(relateRule.getBalanceFlag())) {
              mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), detail.getAmount()));
            } else {
              mertchSubject.setAcctBal(detail.getAmount());
            }
            this.merchAccountDividendList.add(detail);
            this.merchantSubjectList.add(mertchSubject);
          }
        }
        AccountingRuleVO platRule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.LIABILITIES
          .value(), DzConstants.balType.REAL_TIME.value());
        detail = new MerchAccountDividendVO();
        detail.setSubjectCode(platRule.getSubjectCode());
        detail.setSubSubjectCode(platRule.getSubSubjectCode());
        detail.setTradeNo(this.tranInfoVO.getTradeNo());
        detail.setMerchantCode(this.platMerchantCode);
        detail.setLoanFlag(platRule.getLoanFlag());
        detail.setAmount(this.tranInfoVO.getPaymentAmount());
        detail.setMerchantCode1(this.tranInfoVO.getPayer());
        detail.setAccountingDate(this.accountingDate);
        mertchSubject = new MerchantSubjectAccVO();
        mertchSubject.setMerchantCode(detail.getMerchantCode());
        mertchSubject.setSubSubjectCode(detail.getSubSubjectCode());
        mertchSubject.setAcctBal(BigDecimalUtil.sub(BigDecimal.valueOf(0L), detail.getAmount()));
        this.merchantSubjectList.add(mertchSubject);
        this.merchAccountDividendList.add(detail);
      }
      else
      {
        MerchAccountDividendVO bankSubjetDividend = new MerchAccountDividendVO();
        MerchantSubjectAccVO bankSubject = new MerchantSubjectAccVO();
        
        SubjectVO subjectVO = this.accountingDAO.queryBankAccount(this.tranInfoVO.getChannelCode());
        this.bankSubjectCode = subjectVO.getSubjectCode();
        bankSubjetDividend.setTradeNo(this.tranInfoVO.getTradeNo());
        bankSubjetDividend.setMerchantCode(this.platMerchantCode);
        bankSubjetDividend.setLoanFlag(DzConstants.borrowOrLoanFlag.BORROW_FLAG.value());
        bankSubjetDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        bankSubjetDividend.setMerchantCode1(this.tranInfoVO.getPayer());
        bankSubjetDividend.setAccountingDate(this.accountingDate);
        bankSubjetDividend.setSubSubjectCode(this.bankSubjectCode);
        bankSubjetDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        
        bankSubject.setMerchantCode(this.platMerchantCode);
        bankSubject.setSubSubjectCode(this.bankSubjectCode);
        bankSubject.setAcctBal(this.tranInfoVO.getPaymentAmount());
        
        this.merchantSubjectList.add(bankSubject);
        this.merchAccountDividendList.add(bankSubjetDividend);
        
        MerchAccountDividendVO preIncomeDividend = new MerchAccountDividendVO();
        MerchantSubjectAccVO preIncomeSubject = new MerchantSubjectAccVO();
        
        AccountingRuleVO platRule = this.accountingDAO.queryAssetsAccountRuleByServiceNo(this.tranInfoVO.getServiceNo(), DzConstants.subjectType.LIABILITIES
          .value(), DzConstants.balType.REAL_TIME.value());
        preIncomeDividend.setTradeNo(this.tranInfoVO.getTradeNo());
        preIncomeDividend.setMerchantCode(this.platMerchantCode);
        preIncomeDividend.setLoanFlag(DzConstants.borrowOrLoanFlag.LOAN_FLAG.value());
        preIncomeDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        preIncomeDividend.setMerchantCode1(this.tranInfoVO.getPayer());
        preIncomeDividend.setAccountingDate(this.accountingDate);
        preIncomeDividend.setSubSubjectCode(platRule.getSubSubjectCode());
        preIncomeDividend.setSubjectCode(platRule.getSubjectCode());
        preIncomeDividend.setAmount(this.tranInfoVO.getPaymentAmount());
        
        preIncomeSubject.setMerchantCode(this.platMerchantCode);
        preIncomeSubject.setSubSubjectCode(platRule.getSubSubjectCode());
        preIncomeSubject.setAcctBal(this.tranInfoVO.getPaymentAmount());
        
        this.merchantSubjectList.add(preIncomeSubject);
        this.merchAccountDividendList.add(preIncomeDividend);
      }
    }
    catch (Exception e)
    {
      LogUtil.error("处理总账户异常", e);
      throw e;
    }
    return this;
  }
  
  private OnlineCardToMerchantPOJO addTranSubToAccountDetailList()
    throws Exception
  {
    try
    {
      if (this.isSaveMoney) {
        return this;
      }
      AccountingRuleVO    rule = null;
      MerchAccountDividendVO     detail = null;
      if (!CollectionUtils.isEmpty(this.merchantTranSubList)) {
        for (TranSubVO tmp : this.merchantTranSubList)
        {
          rule = new AccountingRuleVO();
          detail = new MerchAccountDividendVO();
          rule.setSubServiceNo(tmp.getServiceNo());
          rule.setServiceNo(this.tranInfoVO.getServiceNo());
          if (DzConstants.isSelfMerchant.SELF.value().equals(tmp.getReceiverIsSelf()))
          {
            rule = this.accountingDAO.queryRecieverAccountingRule(rule);
            setAccountDetail(rule, detail, tmp);
            detail.setMerchantCode1(this.tranInfoVO.getPayer());
          }
          else
          {
            rule.setCprtBalType(DzConstants.balType.PERIODIC_CLEARING.value());
            rule = this.accountingDAO.queryRecieverAccountingRule(rule);
            setAccountDetail(rule, detail, tmp);
            detail.setMerchantCode1(this.platMerchantCode);
          }
          this.merchAccountDividendList.add(detail);
          this.merchantSubjectList.add(setMerchantSubject(detail, rule.getBalanceFlag()));
        }
      }
    }
    catch (Exception e)
    {
      AccountingRuleVO rule;
      MerchAccountDividendVO detail;
      LogUtil.error("交易分录转换成运营商账户分录失败,参数为" + this.merchantTranSubList, e);
      throw e;
    }
    return this;
  }
  
  private void setAccountDetail(AccountingRuleVO rule, MerchAccountDividendVO detail, TranSubVO tmp)
  {
    detail.setAccountingDate(this.accountingDate);
    detail.setMerchantCode(tmp.getReceiver());
    detail.setAmount(tmp.getPaymentAmount());
    detail.setLoanFlag(rule.getLoanFlag());
    detail.setSubjectCode(rule.getSubjectCode());
    detail.setSubSubjectCode(rule.getSubSubjectCode());
    detail.setTradeNo(this.tranInfoVO.getTradeNo());
  }
  
  public void saveAccountDividend()
    throws Exception
  {
    init().assemblePayerAccountDetail().assembleReceiveAccountDetail().addTotalaccount().addTranSubToAccountDetailList();
    if (null == this.accountDetailVO) {
      throw new BusinessException("个人账户明细为空，请检查业务逻辑。");
    }
    this.merchAccountDividendList = mergeMerchAccountDividend(this.merchAccountDividendList);
    
    int[] mc = this.accountingDAO.insertMerchAccountDividend(this.merchAccountDividendList);
    judgeResult(mc, "插入运营商账户分录，参数为：" + this.merchAccountDividendList);
    

    List<AccountDetailVO> accountDetailList = new ArrayList();
    accountDetailList.add(this.accountDetailVO);
    int[] n = this.accountingDAO.insertAccountDetail(accountDetailList);
    judgeResult(n, "插入个人账户明细条数异常，参数accountDetailList为：" + accountDetailList);
  }
  
  public void transferAccountsRealTime()
    throws Exception
  {}
}
